package com.mobilezu.mobile.pushserver.xmpp.session;

import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import com.mobilezu.mobile.pushserver.xmpp.net.Connection;


public abstract class Session {

	public static final int MAJOR_VERSION = 1;
	public static final int MINOR_VERSION = 0;
	public static final int STATUS_CLOSED = 0;
	public static final int STATUS_CONNECTED = 1;
	public static final int STATUS_AUTHENTICATED = 2;
	private static final Log log = LogFactory.getLog(Session.class);
	protected Connection connection;
	protected SessionManager sessionManager;
	private String serverName;
	private JID address;
	private String streamID;
	private int status = STATUS_CONNECTED;
	private long startDate = System.currentTimeMillis();
	private long lastActiveDate;
	private long clientPacketCount = 0;
	private long serverPacketCount = 0;
	private final Map<String, Object> sessionData = new HashMap<String, Object>();

	/**
	 * ����һ��JID
	 * 
	 * @param serverName
	 *            the server name
	 * @param conn
	 *            the connection
	 * @param streamID
	 *            the stream ID
	 */
	public Session(String serverName, Connection conn, String streamID) {
		this.connection = conn;
		this.sessionManager = SessionManager.getInstance();
		this.serverName = serverName;
		this.streamID = streamID;
		this.address = new JID(null, serverName, streamID, true);
	}

	/**
	 * ȡ�ûỰ������
	 * 
	 * @return the connection for this session
	 */
	public Connection getConnection() {
		return connection;
	}

	/**
	 * ȡ�÷�������
	 * 
	 * @return the server name
	 */
	public String getServerName() {
		return serverName;
	}

	/**
	 * ȡ�ûỰ����ID
	 * 
	 * @return the stream ID of this session
	 */
	public String getStreamID() {
		return streamID;
	}

	/**
	 * ȡ���û���JID�ĵ�ַ
	 * 
	 * @return the address of this session
	 */
	public JID getAddress() {
		return address;
	}

	/**
	 * ���ûỰ�ĵ�ַ
	 * 
	 * @param address
	 *            the new address of this session
	 */
	public void setAddress(JID address) {
		this.address = address;
	}

	/**
	 * ���ػỰ��״̬
	 * 
	 * @return the status of this session
	 */
	public int getStatus() {
		return status;
	}

	/**
	 * ���ûỰ��״̬
	 * 
	 * @param status
	 *            the new status of this session
	 */
	public void setStatus(int status) {
		this.status = status;
	}

	/**
	 * ��ȡ�Ự�Ĵ���ʱ��
	 * 
	 * @return the creation date of this session
	 */
	public Date getCreationDate() {
		return new Date(startDate);
	}

	/**
	 * ��ȡ�Ự�����ʱ��.
	 * 
	 * @return the last time of this session
	 */
	public Date getLastActiveDate() {
		return new Date(lastActiveDate);
	}

	/**
	 * �������յ��İ�ĸ������
	 */
	public void incrementClientPacketCount() {
		clientPacketCount++;
		lastActiveDate = System.currentTimeMillis();
	}

	/**
	 * ���������͵İ�ĸ������
	 */
	public void incrementServerPacketCount() {
		serverPacketCount++;
		lastActiveDate = System.currentTimeMillis();
	}

	/**
	 * ��ȡ�������յ��İ�ĸ���
	 * 
	 * @return the number of packets
	 */
	public long getNumClientPackets() {
		return clientPacketCount;
	}

	/**
	 * ��ȡ���������͵İ�ĸ���
	 * 
	 * @return the number of packets
	 */
	public long getNumServerPackets() {
		return serverPacketCount;
	}

	public void setSessionData(String key, Object value) {
		synchronized (sessionData) {
			sessionData.put(key, value);
		}
	}

	public Object getSessionData(String key) {
		synchronized (sessionData) {
			return sessionData.get(key);
		}
	}

	public void removeSessionData(String key) {
		synchronized (sessionData) {
			sessionData.remove(key);
		}
	}

	/**
	 * �����
	 * 
	 * @param packet
	 *            the packet to process
	 */
	public void process(Packet packet) {
		try {
			deliver(packet);
		} catch (Exception e) {
			log.error("Internal server error", e);
		}
	}

	/**
	 * ���Ͱ�
	 * 
	 * @param packet
	 *            the packet to deliver
	 */
	public void deliver(Packet packet) {
		if (connection != null && !connection.isClosed()) {
			connection.deliver(packet);
		}
	}

	/**
	 * ����ԭ�ı�
	 * 
	 * @param text
	 *            the XML stanza string to deliver
	 */
	public void deliverRawText(String text) {
		if (connection != null) {
			connection.deliverRawText(text);
		}
	}

	/**
	 * �رջỰ����ص�socket����
	 */
	public void close() {
		if (connection != null) {
			connection.close();
		}
	}

	/**
	 * �ж������Ƿ��Ѿ��ر�
	 * 
	 * @return true if the connection is closed, flase otherwise.
	 */
	public boolean isClosed() {
		return connection.isClosed();
	}

	// public boolean isSecure() {
	// return connection.isSecure();
	// }

	// public boolean validate() {
	// return connection.validate();
	// }

	/**
	 * ��ȡIP��ַ
	 * 
	 * @return the IP address
	 */
	public String getHostAddress() throws UnknownHostException {
		return connection.getHostAddress();
	}

	/**
	 * ��ȡ������
	 * 
	 * @return the host name for this IP address
	 */
	public String getHostName() throws UnknownHostException {
		return connection.getHostName();
	}

	/**
	 * ��ȡ���������ܵ��ı�
	 */
	public abstract String getAvailableStreamFeatures();

	@Override
	public String toString() {
		return super.toString() + " status: " + status + " address: " + address
				+ " id: " + streamID;
	}

}
